package com.bjy.qa.agent.transport.command;

import com.alibaba.fastjson.JSONObject;
import com.bjy.qa.agent.context.Context;
import com.bjy.qa.agent.exception.MyException;
import com.bjy.qa.agent.model.KeyValueStore;
import com.bjy.qa.agent.response.Response;
import com.bjy.qa.agent.tester.LogUtil;
import com.bjy.qa.agent.transport.websocket.EndingType;
import com.bjy.qa.agent.transport.websocket.IWebSocketService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.util.List;

/**
 * WebSocket 执行器
 */
public class WebSocketExecuteCommand extends ExecuteCommand {
    protected static final Logger logger = LoggerFactory.getLogger(WebSocketExecuteCommand.class);

    protected String handleClass; // WebSocket 处理类名称
    protected String url; // 请求 url
    protected String method; // 方法（send、receive）
    protected String channel; // 通道
    protected List<KeyValueStore> params; // url 参数列表
    private IWebSocketService iWebSocketService;

    /**
     * 构造函数
     * @param handleClass WebSocket 处理类名称
     * @param context 上下文
     * @param resultId 运行结果 id
     * @param caseId 用例 id
     * @param ic 迭代次数（iteration count）
     * @param desc 用例描述
     * @param method 方法（send、receive）
     * @param url 请求 url
     * @param channel 通道
     * @param urlParams url 参数列表
     */
    public WebSocketExecuteCommand(String handleClass, Context context, LogUtil logUtil, String resultId, String caseId, String ic, String desc, String method, String url, String channel, List<KeyValueStore> urlParams, EndingType endingType) {
        super(resultId, caseId, ic, desc);
        if (handleClass == null) {
            this.handleClass = "com.bjy.qa.agent.transport.websocket.WebSocketService";
        } else {
            this.handleClass = handleClass;
        }
        this.url = url;
        this.method = method;
        this.channel = channel;
        this.params = urlParams;

        iWebSocketService = context.getWebSocketService(url, resultId, caseId, channel); // 从上下文中获取 WebSocketService
        if (iWebSocketService == null) { // 如果 WebSocketService 不存在，则创建一个并添加到上下文中
            try {
                Class clazz = Class.forName(this.handleClass);
                Constructor constructor = clazz.getConstructor(Context.class, LogUtil.class, EndingType.class, String.class, List.class);
                iWebSocketService = (IWebSocketService) constructor.newInstance(context, logUtil, endingType, url, urlParams);
                context.addWebSocketService(url, resultId, caseId, channel, iWebSocketService);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("加载 WebSocket 处理类错误，className：" + this.handleClass + "\t" + e.getMessage() );
                throw new MyException("加载 WebSocket 处理类错误，className：" + this.handleClass + "\n" + e.getMessage());
            }
        }
    }

    /**
     * 执行命令，实现了父类的抽象方法，也是主功能
     * @param paramList 参数列表
     * @return
     */
    @Override
    public Response execute(List<KeyValueStore> paramList) {
        String sendBody = null; // 消息体
        long sendInterval = 0; // 发送间隔
        boolean lose = false; // 是否丢弃
        String assertStr = null; // assert 断言
        String setStr = null; // 保存变量
        JSONObject options = null; // WebSocket 扩展数据（通道、服务器是否要关闭连接）

        // 从 paramList 中解析参数
        for (KeyValueStore kvs : paramList) {
            switch (kvs.getName()) {
                case "param":
                    sendBody = kvs.getValue().toString();
                    break;
                case "sendInterval":
                    sendInterval = Long.parseLong(kvs.getValue().toString());
                    break;
                case "lose":
                    lose = Boolean.parseBoolean(kvs.getValue().toString());
                    break;
                case "assertStr":
                    assertStr = kvs.getValue().toString();
                    break;
                case "setStr":
                    setStr = kvs.getValue().toString();
                    break;
                case "options":
                    options = (JSONObject) kvs.getValue();
                    break;
                default:
                    break;
            }
        }

        if ("send".equals(this.method)) {
            this.iWebSocketService.send(sendBody, sendInterval, assertStr, setStr, lose, options);
        } else if ("receive".equals(this.method)) {
            this.iWebSocketService.receive(sendBody, sendInterval, assertStr, setStr, lose, options);
        }

        return null;
    }

    /**
     * 获得测试报告（测试结果上报使用）
     * @return
     */
    @Override
    public String toReportInfo() {
        return String.format("使用 %s 方式调用 HTTP 接口 %s", new Object[]{StringUtils.isBlank(this.method) ? "get" : this.method, showReportUrlWithLink(this.url, this.params)});
    }

    /**
     * 返回包裹在 html a 标签中的 URL（只有 get 请求会包裹在 a 标签中），如果有参数也会带上
     * @param url URL
     * @param params 参数列表
     * @return
     */
    protected String showReportUrlWithLink(String url, List<KeyValueStore> params) {
        if (!"get".equals(this.method)) return url;
        StringBuilder urlBuffer = new StringBuilder();
        urlBuffer.append("<a href=\"").append(url).append("?");
        if ((params != null) && (!params.isEmpty())) {
            for (KeyValueStore param : params) {
                urlBuffer.append(param.getName()).append("=").append(param.getValue()).append("&");
            }
            urlBuffer.deleteCharAt(urlBuffer.lastIndexOf("&"));
        }
        urlBuffer.append("\">").append(url).append("</a>");
        return urlBuffer.toString();
    }
}
